package show.lmm.webflux.handler.method.core.filter;

import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import show.lmm.webflux.handler.method.core.annotation.NotNeedLogin;

import java.nio.charset.StandardCharsets;

@Component
public class AuthWebFilter implements WebFilter {

    private final RequestMappingHandlerMapping handlerMapping;

    public AuthWebFilter(RequestMappingHandlerMapping handlerMapping){
        this.handlerMapping = handlerMapping;
    }
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return handlerMapping.getHandler(exchange).flatMap((res)->{
            HandlerMethod method = exchange.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);
            if(method != null && !method.hasMethodAnnotation(NotNeedLogin.class)){
                return errorResponse(exchange,"需要登录");
            }
            return chain.filter(exchange);
        });
    }

    /**
     * 输出错误消息
     * @param errMsg 错误消息
     */
    private static Mono<Void> errorResponse(ServerWebExchange exchange,String errMsg) {
        final ServerHttpResponse response = exchange.getResponse();
        final DataBufferFactory factory = response.bufferFactory();
        response.setStatusCode(HttpStatus.OK);
        final HttpHeaders headers = response.getHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return response.writeWith(Flux.just(factory.wrap(errMsg.getBytes(StandardCharsets.UTF_8))));
    }
}
